//! 成交量价格特征模块
//! 
//! 提供成交量价格相关的特征计算

use serde::{Deserialize, Serialize};
use crate::objects::RawBar;

/// 成交量价格特征配置
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct VpfConfig {
    /// 成交量分析周期
    pub volume_period: usize,
    /// 价格成交量关系分析周期
    pub price_volume_period: usize,
    /// 资金流向分析周期
    pub money_flow_period: usize,
}

/// 成交量价格特征计算器
#[derive(Debug, Clone)]
pub struct VpfFeatures {
    config: VpfConfig,
}

impl VpfFeatures {
    /// 创建新的成交量价格特征计算器
    pub fn new(config: VpfConfig) -> Self {
        Self { config }
    }

    /// 计算成交量移动平均
    pub fn volume_ma(&self, volumes: &[f64], period: usize) -> Vec<f64> {
        if volumes.len() < period {
            return vec![];
        }
        
        let mut ma_values = Vec::new();
        for i in period - 1..volumes.len() {
            let sum: f64 = volumes[i - period + 1..=i].iter().sum();
            ma_values.push(sum / period as f64);
        }
        ma_values
    }

    /// 计算成交量比率
    pub fn volume_ratio(&self, volumes: &[f64], period: usize) -> Vec<f64> {
        if volumes.len() < period {
            return vec![];
        }
        
        let volume_ma = self.volume_ma(volumes, period);
        let mut ratios = Vec::new();
        
        for i in period - 1..volumes.len() {
            let ratio = if volume_ma[i - period + 1] != 0.0 {
                volumes[i] / volume_ma[i - period + 1]
            } else {
                1.0
            };
            ratios.push(ratio);
        }
        
        ratios
    }

    /// 计算价格成交量趋势
    pub fn price_volume_trend(&self, bars: &[RawBar]) -> Vec<f64> {
        if bars.len() < 2 {
            return vec![];
        }
        
        let mut pvt = Vec::new();
        let mut cumulative_pvt = 0.0;
        
        for i in 1..bars.len() {
            let price_change = (bars[i].close - bars[i-1].close) / bars[i-1].close;
            let volume_ratio = bars[i].vol / bars[i-1].vol;
            let pvt_change = price_change * volume_ratio;
            cumulative_pvt += pvt_change;
            pvt.push(cumulative_pvt);
        }
        
        pvt
    }

    /// 计算资金流向指标 (Money Flow Index)
    pub fn money_flow_index(&self, bars: &[RawBar], period: usize) -> Vec<f64> {
        if bars.len() < period + 1 {
            return vec![];
        }
        
        let mut typical_prices = Vec::new();
        let mut money_flows = Vec::new();
        
        for bar in bars {
            let typical_price = (bar.high + bar.low + bar.close) / 3.0;
            typical_prices.push(typical_price);
        }
        
        for i in 1..bars.len() {
            let positive_flow = if typical_prices[i] > typical_prices[i-1] {
                typical_prices[i] * bars[i].vol
            } else {
                0.0
            };
            let negative_flow = if typical_prices[i] < typical_prices[i-1] {
                typical_prices[i] * bars[i].vol
            } else {
                0.0
            };
            money_flows.push((positive_flow, negative_flow));
        }
        
        let mut mfi_values = Vec::new();
        for i in period - 1..money_flows.len() {
            let positive_sum: f64 = money_flows[i - period + 1..=i]
                .iter()
                .map(|(pos, _)| pos)
                .sum();
            let negative_sum: f64 = money_flows[i - period + 1..=i]
                .iter()
                .map(|(_, neg)| neg)
                .sum();
            
            let mfi = if negative_sum != 0.0 {
                100.0 - (100.0 / (1.0 + positive_sum / negative_sum))
            } else {
                100.0
            };
            mfi_values.push(mfi);
        }
        
        mfi_values
    }

    /// 计算成交量加权平均价格 (VWAP)
    pub fn vwap(&self, bars: &[RawBar]) -> Vec<f64> {
        if bars.is_empty() {
            return vec![];
        }
        
        let mut vwap_values = Vec::new();
        let mut cumulative_pv = 0.0;
        let mut cumulative_volume = 0.0;
        
        for bar in bars {
            let typical_price = (bar.high + bar.low + bar.close) / 3.0;
            cumulative_pv += typical_price * bar.vol;
            cumulative_volume += bar.vol;
            
            let vwap = if cumulative_volume != 0.0 {
                cumulative_pv / cumulative_volume
            } else {
                typical_price
            };
            vwap_values.push(vwap);
        }
        
        vwap_values
    }

    /// 计算成交量价格趋势 (Volume Price Trend)
    pub fn volume_price_trend(&self, bars: &[RawBar]) -> Vec<f64> {
        if bars.is_empty() {
            return vec![];
        }
        
        let mut vpt_values = Vec::new();
        let mut cumulative_vpt = 0.0;
        
        for i in 1..bars.len() {
            let price_change = (bars[i].close - bars[i-1].close) / bars[i-1].close;
            let volume_change = bars[i].vol - bars[i-1].vol;
            let vpt_change = price_change * volume_change;
            cumulative_vpt += vpt_change;
            vpt_values.push(cumulative_vpt);
        }
        
        vpt_values
    }

    /// 计算成交量相对强弱指标 (Volume RSI)
    pub fn volume_rsi(&self, volumes: &[f64], period: usize) -> Vec<f64> {
        if volumes.len() < period + 1 {
            return vec![];
        }
        
        let mut volume_changes = Vec::new();
        for i in 1..volumes.len() {
            volume_changes.push(volumes[i] - volumes[i-1]);
        }
        
        let mut gains = Vec::new();
        let mut losses = Vec::new();
        
        for change in &volume_changes {
            gains.push(change.max(0.0));
            losses.push((-change).max(0.0));
        }
        
        let mut volume_rsi_values = Vec::new();
        for i in period - 1..gains.len() {
            let avg_gain: f64 = gains[i - period + 1..=i].iter().sum::<f64>() / period as f64;
            let avg_loss: f64 = losses[i - period + 1..=i].iter().sum::<f64>() / period as f64;
            
            let rs = if avg_loss != 0.0 { avg_gain / avg_loss } else { 0.0 };
            let rsi = 100.0 - (100.0 / (1.0 + rs));
            volume_rsi_values.push(rsi);
        }
        
        volume_rsi_values
    }

    /// 计算成交量价格背离
    pub fn volume_price_divergence(&self, bars: &[RawBar], period: usize) -> Vec<bool> {
        if bars.len() < period {
            return vec![];
        }
        
        let prices: Vec<f64> = bars.iter().map(|bar| bar.close).collect();
        let volumes: Vec<f64> = bars.iter().map(|bar| bar.vol).collect();
        
        let mut divergences = Vec::new();
        
        for i in period - 1..bars.len() {
            let price_window = &prices[i - period + 1..=i];
            let volume_window = &volumes[i - period + 1..=i];
            
            let price_trend = price_window.last().unwrap() - price_window.first().unwrap();
            let volume_trend = volume_window.last().unwrap() - volume_window.first().unwrap();
            
            // 价格上升但成交量下降，或价格下降但成交量上升
            let divergence = (price_trend > 0.0 && volume_trend < 0.0) || 
                           (price_trend < 0.0 && volume_trend > 0.0);
            divergences.push(divergence);
        }
        
        divergences
    }

    /// 计算成交量分布
    pub fn volume_distribution(&self, volumes: &[f64], bins: usize) -> Vec<f64> {
        if volumes.is_empty() {
            return vec![];
        }
        
        let min_volume = volumes.iter().fold(f64::INFINITY, |a, &b| a.min(b));
        let max_volume = volumes.iter().fold(f64::NEG_INFINITY, |a, &b| a.max(b));
        
        if min_volume == max_volume {
            return vec![volumes.len() as f64];
        }
        
        let bin_size = (max_volume - min_volume) / bins as f64;
        let mut distribution = vec![0.0; bins];
        
        for &volume in volumes {
            let bin_index = ((volume - min_volume) / bin_size).min(bins as f64 - 1.0) as usize;
            distribution[bin_index] += 1.0;
        }
        
        distribution
    }

    /// 计算所有成交量价格特征
    pub fn calculate_all_features(&self, bars: &[RawBar]) -> serde_json::Value {
        if bars.is_empty() {
            return serde_json::json!({
                "error": "K线数据为空，无法计算特征"
            });
        }
        
        let volumes: Vec<f64> = bars.iter().map(|bar| bar.vol).collect();
        
        // 计算各种成交量价格特征
        let volume_ma_20 = self.volume_ma(&volumes, 20);
        let volume_ratio_20 = self.volume_ratio(&volumes, 20);
        let pvt = self.price_volume_trend(bars);
        let mfi = self.money_flow_index(bars, 14);
        let vwap = self.vwap(bars);
        let vpt = self.volume_price_trend(bars);
        let volume_rsi = self.volume_rsi(&volumes, 14);
        let divergence = self.volume_price_divergence(bars, 20);
        let volume_dist = self.volume_distribution(&volumes, 10);
        
        serde_json::json!({
            "volume_ma_20": volume_ma_20,
            "volume_ratio_20": volume_ratio_20,
            "price_volume_trend": pvt,
            "money_flow_index": mfi,
            "vwap": vwap,
            "volume_price_trend": vpt,
            "volume_rsi": volume_rsi,
            "volume_price_divergence": divergence,
            "volume_distribution": volume_dist,
            "volume_statistics": {
                "total_volume": volumes.iter().sum::<f64>(),
                "avg_volume": volumes.iter().sum::<f64>() / volumes.len() as f64,
                "max_volume": volumes.iter().fold(f64::NEG_INFINITY, |a, &b| a.max(b)),
                "min_volume": volumes.iter().fold(f64::INFINITY, |a, &b| a.min(b))
            },
            "feature_count": {
                "volume_ma": volume_ma_20.len(),
                "volume_ratio": volume_ratio_20.len(),
                "pvt": pvt.len(),
                "mfi": mfi.len(),
                "vwap": vwap.len(),
                "vpt": vpt.len(),
                "volume_rsi": volume_rsi.len(),
                "divergence": divergence.len()
            }
        })
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::objects::{RawBar, Freq};
    use chrono::Utc;

    #[test]
    fn test_volume_ma() {
        let config = VpfConfig {
            volume_period: 5,
            price_volume_period: 10,
            money_flow_period: 14,
        };
        let vpf_features = VpfFeatures::new(config);
        
        let volumes = vec![100.0, 200.0, 300.0, 400.0, 500.0, 600.0];
        let ma = vpf_features.volume_ma(&volumes, 5);
        
        assert_eq!(ma.len(), 2);
        assert_eq!(ma[0], 300.0); // (100+200+300+400+500)/5
        assert_eq!(ma[1], 400.0); // (200+300+400+500+600)/5
    }

    #[test]
    fn test_volume_ratio() {
        let config = VpfConfig {
            volume_period: 5,
            price_volume_period: 10,
            money_flow_period: 14,
        };
        let vpf_features = VpfFeatures::new(config);
        
        let volumes = vec![100.0, 200.0, 300.0, 400.0, 500.0, 600.0];
        let ratio = vpf_features.volume_ratio(&volumes, 5);
        
        assert_eq!(ratio.len(), 2);
        assert_eq!(ratio[0], 500.0 / 300.0); // 500/300
        assert_eq!(ratio[1], 600.0 / 400.0); // 600/400
    }

    #[test]
    fn test_vwap() {
        let config = VpfConfig {
            volume_period: 5,
            price_volume_period: 10,
            money_flow_period: 14,
        };
        let vpf_features = VpfFeatures::new(config);
        
        let bars = vec![
            RawBar {
                symbol: "TEST".to_string(),
                id: 1,
                freq: Freq::Day,
                dt: Utc::now(),
                open: 100.0,
                close: 110.0,
                high: 115.0,
                low: 95.0,
                vol: 1000.0,
                amount: 110000.0,
                cache: Default::default(),
            }
        ];
        
        let vwap = vpf_features.vwap(&bars);
        assert_eq!(vwap.len(), 1);
        assert!((vwap[0] - 106.67).abs() < 0.01); // (115+95+110)/3
    }
} 